package com.hot12345.database;

import java.lang.reflect.ParameterizedType;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.hot12345.server.DBConnection.IbatisConnectCommImpl;

import com.ibatis.sqlmap.client.SqlMapClient;
import com.hot12345.common.util.MapUtil;

public class BaseDaoImpl<T> implements BaseDao<T> {
/**
 * @todo:继承类应该采用Factory工厂模式,实现dao的Single模式,避免外面使用的时候不断地 new 对象产生大量重复对象
 */
	private Log logger = LogFactory.getLog(this.getClass());
	// model's Class
	protected Class<T> entityClass;

	// model's ClassName
	protected String entityClassName;
	
	protected Class<T> superClzClass;
	private String RDS;//默认的只读数据源名称
	private String WDS;//默认的只写数据源名称
	
	@SuppressWarnings("unchecked")
	public BaseDaoImpl() {
		try {			
			Object genericClz=getClass().getGenericSuperclass();
			RDS = (String)getClass().getField("RDS").get("RDS");
			WDS = (String)getClass().getField("WDS").get("WDS");
			
			if(RDS==null){		
				throw new Exception("找不到子类中定义的默认只读数据源");
			}
			if(WDS==null){		
				throw new Exception("找不到子类中定义的默认只写数据源");
			}
			if(genericClz instanceof ParameterizedType) {				
				entityClass = (Class<T>) ((ParameterizedType)genericClz).getActualTypeArguments()[0];
				entityClassName = entityClass.getSimpleName();
			}

			//logger.debug("dao entityClassName=" + entityClassName);
		} catch (RuntimeException e) {
			logger.error("RuntimeException" ,e);
		} catch (NoSuchFieldException e) {
			logger.error("NoSuchFieldException",e);
		} catch (Exception e) {
			logger.error("Exception",e);
		}
	}
	
	/**
	 * get the entity class name ，such as "User"
	 */
	protected String getEntityName() {
		return this.entityClassName;
		//return ClassUtils.getShortName(GenericsUtils.getGenericClass(getClass()));
	}
	
	/**
	 * @param entityClass the entityClass to set
	 */
	public void setEntityClass(Class<T> entityClass) {
		this.entityClass = entityClass;
		entityClassName = entityClass.getSimpleName();
	}
	
	public T findByPrimaryKey(Integer id) throws Exception{
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("id", id);
		params.put("!state", -1);
		return findUniqueByParams(params);
	}
	
	@SuppressWarnings("unchecked")
	public T findUniqueByParams(Map<String, Object> params) throws Exception {
		String findSqlMapId = getEntityName() + "." + PRE_FIND;
		SqlMapClient sqlClient = IbatisConnectCommImpl.getSqlMapClient(RDS);
		try {
		    List<T> list= sqlClient.queryForList(
		    		findSqlMapId, params);
		    if(list==null||list.size()==0){
		        return null;
		    }else if(list.size()==1){
		        return list.get(0);
		    }else{
		    	MapUtil.printMap(params);
		    	logger.error("jdbc.error.code.Common.findUniqueByParams.notUique,list.size="+list.size());
		        throw new SQLException("jdbc.error.code.Common.findUniqueByParams.notUiqueid="+params.get("id"));
		    }
		} catch (Exception e) {
			MapUtil.printMap(params);
			logger.error("SQLException",e);
			throw e;
			// throw new SQLException("jdbc.error.code.Common.findUniqueByParams.notUique,id="+params.get("id"));
		}
	}
	
	@SuppressWarnings("unchecked")
	public List<T> findByParams(Map<String, Object> params) throws Exception{
		if(params==null){
			params=new HashMap<String, Object>();
		}
		String findSqlMapId = getEntityName() + "." + PRE_FIND;
		logger.debug("findSqlMapId=" + findSqlMapId);
//		logger.warn("数据源"+RDS);
		SqlMapClient sqlClient = IbatisConnectCommImpl.getSqlMapClient(RDS);
		try {
			return (List<T>) sqlClient.queryForList(
					findSqlMapId, params);
		} catch (SQLException e) {
			logger.error("SQLException ",e);
			 throw new SQLException("jdbc.error.findByParams"+e);
		}
	}
	
	public Integer insert(T entity) throws Exception{
		if(entity==null){
			return null;
		}
		String insertSqlMapId = getEntityName() + "." + PRE_INSERT;
		logger.debug("insertSqlMapId=" + insertSqlMapId);
		Integer id=null;
 
		SqlMapClient sqlClient = IbatisConnectCommImpl.getSqlMapClient(WDS);
 
		try {
			id=(Integer)sqlClient.insert(insertSqlMapId, entity);			 
		} catch (Exception e) {  
			logger.error("SQLException " ,e);
//			logger.error("数据库服务器url" +((ProxoolDataSource)sqlClient.getDataSource()).getDriverUrl());
//			logger.error("数据库服务器IP" +java.net.InetAddress.getByName(((ProxoolDataSource)sqlClient.getDataSource()).getDriverUrl()).getHostAddress());
			throw new Exception("jdbc.error.insert"+e);  
		} 
	 
		return id;  
	}

	public Long insertL(T entity) throws Exception{
		if(entity==null){
			return null;
		}
		String insertSqlMapId = getEntityName() + "." + PRE_INSERT;
		logger.debug("insertSqlMapId=" + insertSqlMapId);
		Long id=null;
		SqlMapClient sqlClient = IbatisConnectCommImpl.getSqlMapClient(WDS);
//		logger.error("dataSoure=" + WDS);
		try {
			id = (Long)sqlClient.insert(insertSqlMapId, entity);
		} catch (SQLException e) {
//			logger.error("数据库服务器url" +((ProxoolDataSource)sqlClient.getDataSource()).getDriverUrl());
//			logger.error("数据库服务器IP" +java.net.InetAddress.getByName(((ProxoolDataSource)sqlClient.getDataSource()).getDriverUrl()).getHostAddress());
			logger.error("SQLException " ,e);
			throw new Exception("jdbc.error.insertL");  
		} 
		return id;
	}
	
	public Integer delete(T entity) throws Exception{
		String deleteSqlMapId = getEntityName() + "." + PRE_DELETE;
		logger.debug("deleteSqlMapId=" + deleteSqlMapId);
		SqlMapClient sqlClient = IbatisConnectCommImpl.getSqlMapClient(WDS);
		try {
			return sqlClient.delete(deleteSqlMapId,
					((BaseEntity) entity).getId());
		} catch (SQLException e) {
			logger.error("SQLException " ,e);
			throw new Exception("jdbc.error.delete");  
		}
	}

	public Integer deleteByParams(Map<String, Object> params) throws Exception{
		String deleteSqlMapId = getEntityName() + "." + PRE_DELETE_BY_PARAMS;
		logger.debug("deleteSqlMapId=" + deleteSqlMapId);
		SqlMapClient sqlClient = IbatisConnectCommImpl.getSqlMapClient(WDS);
		try {
			return sqlClient.delete(deleteSqlMapId,params);
		} catch (SQLException e) {
			logger.error("SQLException " ,e);
			throw new Exception("jdbc.error.deleteByParams");  
		}
	}

	public Integer deleteByPrimaryKey(Integer id) throws Exception{
		String deleteSqlMapId = getEntityName() + "." + PRE_DELETE;
		logger.debug("deleteSqlMapId=" + deleteSqlMapId);
		SqlMapClient sqlClient = IbatisConnectCommImpl.getSqlMapClient(WDS);
		try {
			return sqlClient.delete(deleteSqlMapId, id);
		} catch (SQLException e) {
			logger.error("SQLException " ,e);
			throw new Exception("jdbc.error.deleteByPrimaryKey");  
		}
	}
	
	public Integer deleteByPrimaryKey(Long id) throws Exception{
		String deleteSqlMapId = getEntityName() + "." + PRE_DELETE;
		logger.debug("deleteSqlMapId=" + deleteSqlMapId);
		SqlMapClient sqlClient = IbatisConnectCommImpl.getSqlMapClient(WDS);
		try {
			return sqlClient.delete(deleteSqlMapId, id);
		} catch (SQLException e) {
			logger.error("SQLException " ,e);
			throw new Exception("jdbc.error.deleteByPrimaryKey");  
		}
	}

	public int update(T entity) throws Exception{
		String updateSqlMapId = getEntityName() + "." + PRE_UPDATE;
		logger.debug("updateSqlMapId=" + updateSqlMapId);
		SqlMapClient sqlClient = IbatisConnectCommImpl.getSqlMapClient(WDS);
		int effectCnt = 0;
		try {
			effectCnt = sqlClient.update(updateSqlMapId, entity);
			if(effectCnt==0){
				logger.error("update failure");
				throw new Exception("jdbc.error.update");  
			}
		} catch (SQLException e) {
			logger.error("SQLException " ,e);
//			logger.error("数据库服务器url" +((ProxoolDataSource)sqlClient.getDataSource()).getDriverUrl());
//			logger.error("数据库服务器IP" +java.net.InetAddress.getByName(((ProxoolDataSource)sqlClient.getDataSource()).getDriverUrl()).getHostAddress());
			throw new Exception("jdbc.error.update");  
		}
		return effectCnt;
	}
	
	/**
	 * 根据参数更新数据，这个方法要慎重使用，更新的条件一定要写好，否则造成全表更新就麻烦了。
	 * @param entity
	 * @return int
	 * @throws Exception
	 * @author wuzongbao
	 * @date 2011-10-27 下午07:21:12
	 */
	public int updateByParams(T entity) throws Exception{
		String updateSqlMapId = getEntityName() + "." + PRE_UPDATE_BY_PARAMS;
		logger.debug("updateSqlMapId=" + updateSqlMapId);
		SqlMapClient sqlClient = IbatisConnectCommImpl.getSqlMapClient(WDS);
		int effectCnt = 0;
		try {
			effectCnt = sqlClient.update(updateSqlMapId, entity);
			if(effectCnt==0){
				logger.error("update failure");
				throw new Exception("jdbc.error.update");  
			}
		} catch (SQLException e) {
			logger.error("SQLException " ,e);
			throw new Exception("jdbc.error.update");  
		}
		return effectCnt;
	}
	
	public int updateType2(Object vo) throws Exception{
		String updateSqlMapId = getEntityName() + ".updateType2";
		logger.debug("updateSqlMapId=" + updateSqlMapId);
		SqlMapClient sqlClient = IbatisConnectCommImpl.getSqlMapClient(WDS);
		int effectCnt = 0;
		try {
			effectCnt = sqlClient.update(updateSqlMapId, vo);
			if(effectCnt==0){
				logger.error("update failure,effectCnt=0");
//				throw new Exception("jdbc.error.update");  
			}
		} catch (SQLException e) {
			logger.error("SQLException " ,e);
//			logger.error("数据库服务器url" +((ProxoolDataSource)sqlClient.getDataSource()).getDriverUrl());
//			logger.error("数据库服务器IP" +java.net.InetAddress.getByName(((ProxoolDataSource)sqlClient.getDataSource()).getDriverUrl()).getHostAddress());
			throw new Exception("jdbc.error.update");  
		}
		return effectCnt;
	}
	
	/**
	 * 更新记录数为0即effectCnt==0为0时不抛异常
	 * mengdz
	 * @param entity
	 * @return
	 * @throws Exception
	 */
	public int updateReturn(T entity) throws Exception{
		String updateSqlMapId = getEntityName() + "." + PRE_UPDATE;
		logger.debug("updateSqlMapId=" + updateSqlMapId);
		SqlMapClient sqlClient = IbatisConnectCommImpl.getSqlMapClient(WDS);
		int effectCnt = 0;
		try {
			effectCnt = sqlClient.update(updateSqlMapId, entity);
//			if(effectCnt==0){
//				logger.error("update failure");
//				throw new Exception("jdbc.error.update");  
//			}
		} catch (Exception e) {
			logger.error("SQLException " ,e);
//			logger.error("数据库服务器url" +((ProxoolDataSource)sqlClient.getDataSource()).getDriverUrl());
//			logger.error("数据库服务器IP" +java.net.InetAddress.getByName(((ProxoolDataSource)sqlClient.getDataSource()).getDriverUrl()).getHostAddress());
			throw new Exception("jdbc.error.update");  
		}
		return effectCnt;
	}
	
	/*
	 * 更新收藏数
	 */
	public int updateFavorites(int id) throws Exception{
		String updateSqlMapId = getEntityName() + ".updateFavorites";
		logger.debug("updateSqlMapId=" + updateSqlMapId);
		SqlMapClient sqlClient = IbatisConnectCommImpl.getSqlMapClient(WDS);
		int effectCnt = 0;
		try {
			effectCnt = sqlClient.update(updateSqlMapId, id);
			if(effectCnt==0){
				logger.error("update failure");
				throw new Exception("jdbc.error.update");  
			}
		} catch (SQLException e) {
			logger.error("SQLException " ,e);
			throw new Exception("jdbc.error.update");  
		}
		return effectCnt;
	}
	
	public Object findObjectBySqlID(String sqlID, Map<String, Object> params) throws Exception{
		SqlMapClient sqlClient = IbatisConnectCommImpl.getSqlMapClient(RDS);
		try {
			return sqlClient.queryForObject(sqlID, params);
		} catch (SQLException e) {
			logger.error("SQLException " ,e);
			throw new Exception("jdbc.error.findObjectBySqlID");  
		}
	}

	public List<T> findByPrimaryKeys(Integer[] ids) throws Exception{
		Map<String, Object> params = new HashMap<String, Object>();
		if (ids == null || ids.length == 0) {
			params.put("ids", new Integer(-1));
		} else {
			StringBuffer sb = new StringBuffer();
			for (Integer sid : ids) {
				sb.append("," + sid);
			}
			params.put("ids", sb.deleteCharAt(0).toString());
		}
		return findByParams(params);
	}

	@SuppressWarnings("unchecked")
	public List<T> findByParamsPage(Map<String, Object> params,
			int pageNo, int limit) throws Exception {
		if(params==null){
			params=new HashMap<String, Object>();
		}
		params.put("startNo", pageNo);
		params.put("pageSize", limit);
		String findSqlMapId = getEntityName() + "." + PRE_FIND;
		logger.debug("findSqlMapId=" + findSqlMapId);
		SqlMapClient sqlClient = IbatisConnectCommImpl.getSqlMapClient(RDS);
		try {
			return (List<T>) sqlClient.queryForList(
					findSqlMapId, params);
		} catch (SQLException e) {
			logger.error("SQLException " ,e);
			throw new Exception("jdbc.error.findByParamsPage"+e);
		}
	}
	
	public List findVOByParams(Map<String, Object> params) throws Exception {
		if(params==null){
			params=new HashMap<String, Object>();
		}

		String findSqlMapId = getEntityName() + "." + PRE_FIND_VO;
		logger.debug("findSqlMapId=" + findSqlMapId);
		SqlMapClient sqlClient = IbatisConnectCommImpl.getSqlMapClient(RDS);
		try {
			return (List)sqlClient.queryForList(
					findSqlMapId, params);
		} catch (SQLException e) {
			logger.error("SQLException " ,e);
			throw new Exception("jdbc.error.findByParamsPage"+e);
		}
	}
	
	public List findVOByParamsPage(Map<String, Object> params,
			int pageNo, int limit) throws Exception {
		if(params==null){
			params=new HashMap<String, Object>();
		}
		params.put("startNo", pageNo);
		params.put("pageSize", limit);
		
		return findVOByParams(params);
		
//		String findSqlMapId = getEntityName() + "." + PRE_FIND_VO;
//		logger.debug("findSqlMapId=" + findSqlMapId);
//		SqlMapClient sqlClient = IbatisConnectCommImpl.getSqlMapClient(RDS);
//		try {
//			return (List)sqlClient.queryForList(
//					findSqlMapId, params);
//		} catch (SQLException e) {
//			logger.error("SQLException " ,e);
//			throw new Exception("jdbc.error.findByParamsPage"+e);
//		}
	}
	
	public Object findVOByPrimaryKey(Long id) throws Exception {
		
		Map<String,Object> params = new HashMap<String, Object>();
		params.put("id", id);
		
		String findSqlMapId = getEntityName() + "." + PRE_FIND_VO;
		logger.debug("findSqlMapId=" + findSqlMapId);
		SqlMapClient sqlClient = IbatisConnectCommImpl.getSqlMapClient(RDS);
		try {
		    List list= sqlClient.queryForList(
		    		findSqlMapId, params);
		    if(list==null||list.size()==0){
		        return null;
		    }else if(list.size()==1){
		        return list.get(0);
		    }else{
		    	MapUtil.printMap(params);
		    	logger.error("jdbc.error.code.Common.findUniqueByParams.notUique,list.size="+list.size());
		        throw new SQLException("jdbc.error.code.Common.findUniqueByParams.notUiqueid="+params.get("id"));
		    }
		} catch (Exception e) {
			MapUtil.printMap(params);
			logger.error("SQLException",e);
			throw e;
		}
	}

	public T findByPrimaryKey(Long id) throws Exception {
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("id", id);
		return findUniqueByParams(params);
	}

	public long findCount(Map<String,Object> params) throws Exception{
		if(params==null){
			params=new HashMap<String, Object>();
		}
		String findSqlMapId = getEntityName() + "." + PRE_FIND_COUNT;
		logger.debug("findSqlMapId=" + findSqlMapId);
		SqlMapClient sqlClient = IbatisConnectCommImpl.getSqlMapClient(RDS);
		Object countNum = null;
		try {
			countNum = sqlClient.queryForObject(
					findSqlMapId, params);
		} catch (SQLException e) {
			logger.error("SQLException " ,e);
			throw new Exception("jdbc.error.findByParamsPage");
		}
		if(countNum!=null){
			return (Long)countNum;
		}
		return 0;
	}
	/**
	 * 查询sqlMapID查询总数
	 * @param params
	 * @param sqlMapID
	 * @return long 总数
	 * @throws Exception
	 */
	public long findCount(Map<String,Object> params,String sqlMapID) throws Exception{
		if(params==null){
			params=new HashMap<String, Object>();
		}
		if(sqlMapID==null || "".equals(sqlMapID)){
			logger.error("no SQLMap ID");
			throw new Exception("jdbc.error.noSqlMapID");
		}
		String findSqlMapId = getEntityName() + "." + sqlMapID;
		logger.debug("findSqlMapId=" + findSqlMapId);
		SqlMapClient sqlClient = IbatisConnectCommImpl.getSqlMapClient(RDS);
		Object countNum = null;
		try {
			countNum = sqlClient.queryForObject(
					findSqlMapId, params);
		} catch (SQLException e) {
			logger.error("SQLException " ,e);
			throw new Exception("jdbc.error.findByParamsPage");
		}
		if(countNum!=null){
			return (Long)countNum;
		}
		return 0;
	}
	
	
	
	public  List<T> findDocumentCount(Map<String,Object> params) throws Exception{
		if(params==null){
			params=new HashMap<String, Object>();
		}
		String findSqlMapId = getEntityName() + "." + "findDocumentCount";
		logger.debug("findSqlMapId=" + findSqlMapId);
		SqlMapClient sqlClient = IbatisConnectCommImpl.getSqlMapClient(RDS);
		
		try {
			return (List<T>) sqlClient.queryForList(findSqlMapId, params);
			
		} catch (SQLException e) {
			logger.error("SQLException " ,e);
			throw new Exception("jdbc.error.findByParamsPage");
		}
		
	}
	/*
	 * 更新点击数
	 */
	public int updateClickNum(int id) throws Exception{
		String updateSqlMapId = getEntityName() + ".updateClick";
		logger.debug("updateSqlMapId=" + updateSqlMapId);
		SqlMapClient sqlClient = IbatisConnectCommImpl.getSqlMapClient(WDS);
		int effectCnt = 0;
		try {
			effectCnt = sqlClient.update(updateSqlMapId, id);
			if(effectCnt==0){
				logger.error("update failure");
				throw new Exception("jdbc.error.update");  
			}
		} catch (SQLException e) {
			logger.error("SQLException " ,e);
			throw new Exception("jdbc.error.update");  
		}
		return effectCnt;
	}
	
	/*
	 * 更新回复数
	 */
	public int updateReplycount(int id) throws Exception{
		String updateSqlMapId = getEntityName() + ".updateReplycount";
		logger.debug("updateSqlMapId=" + updateSqlMapId);
		SqlMapClient sqlClient = IbatisConnectCommImpl.getSqlMapClient(WDS);
		int effectCnt = 0;
		try {
			effectCnt = sqlClient.update(updateSqlMapId, id);
			if(effectCnt==0){
				logger.error("update failure");
				throw new Exception("jdbc.error.update");  
			}
		} catch (SQLException e) {
			logger.error("SQLException " ,e);
			throw new Exception("jdbc.error.update");  
		}
		return effectCnt;
	}
	
	
	

	
	
	
	public String getRDS() {
		return RDS;
	}



	public String getWDS() {
		return WDS;
	}

}
